import { DoublyNode } from './linked-list-models';
import { defaultEquals,IEqualsFunction } from './../utils';
import LinkedList from './linked-list';

export default class DoublyLinkedList<T> extends LinkedList<T>{
    protected head: DoublyNode<T> | undefined;
    protected tail: DoublyNode<T> | undefined;

    constructor(protected equalsFn: IEqualsFunction<T> = defaultEquals){
        super(equalsFn);
    }
    push(element: T){
        const node = new DoublyNode(element);
        if(this.head == null){
            this.head = node;
            this.tail = node;
        }else{
            this.tail!.next = node;
            node.prev = this.tail;
            this.tail = node;
        }
        this.count++;
    }
    insert(element:T,index:number){
        if(index >=0 && index < this.count){
            const node = new DoublyNode(element);
            let current = this.head;
            /**在第一个位置插入 */
            if(index === 0){
                // 如果head为空
                if(this.head == null){
                    this.head = node;
                    this.tail = node;
                }else{
                    node.next = this.head;
                    this.head.prev = node;
                    this.head = node;
                }
            }else if(index === this.count){ //在尾部插入
                current = this.tail;
                current!.next = node;
                node.prev = current;
                this.tail = node;
            }else{ // 在中间插入
                const previous = this.getElementAt(index - 1);
                current = previous?.next;
                node.next = current
                previous!.next = node;
                current!.prev = node;
                node.prev = previous;
            }
            this.count++;
            return true;
        }
        return false;
    }
    removeAt(index:number){
        if(index >= 0 && index < this.count){
            let current = this.head;
            if(index === 0){
                this.head = this.head?.next;
                if(this.count === 1){
                    this.tail = undefined;
                }else{
                    this.head!.prev = undefined
                }
            }else if(index === this.count -1){
                current = this.tail;
                this.tail = current?.prev;
                this.tail = undefined;
            }else{
                current = this.getElementAt(index);
                const previous = current?.prev;
                previous!.next = current?.next;
                current!.next!.prev = previous;
            }
            this.count--;
            return current?.element;
        }
        return undefined;
    }
    indexOf(element: T) {
        let current = this.head;
        let index = 0;
    
        while (current != null) {
          if (this.equalsFn(element, current.element)) {
            return index;
          }
          index++;
          current = current.next;
        }
        return -1;
    }
    getHead(){
        return this.head;
    }
    getTail() {
        return this.tail;
    }
    
    clear() {
        super.clear();
        this.tail = undefined;
    }
}